// ============================================================================
// 错误处理系统
// ============================================================================

import { logger } from './logger'

// ============================================================================
// 错误类型定义
// ============================================================================

export enum ErrorCode {
  // 网络错误
  NETWORK_ERROR = 'NETWORK_ERROR',
  TIMEOUT_ERROR = 'TIMEOUT_ERROR',
  CONNECTION_REFUSED = 'CONNECTION_REFUSED',
  
  // 认证错误
  AUTH_FAILED = 'AUTH_FAILED',
  TOKEN_EXPIRED = 'TOKEN_EXPIRED',
  PERMISSION_DENIED = 'PERMISSION_DENIED',
  
  // 数据错误
  INVALID_DATA = 'INVALID_DATA',
  DATA_NOT_FOUND = 'DATA_NOT_FOUND',
  VALIDATION_ERROR = 'VALIDATION_ERROR',
  
  // 业务错误
  TASK_FAILED = 'TASK_FAILED',
  ACCOUNT_INVALID = 'ACCOUNT_INVALID',
  RATE_LIMITED = 'RATE_LIMITED',
  
  // 系统错误
  INTERNAL_ERROR = 'INTERNAL_ERROR',
  FILE_ERROR = 'FILE_ERROR',
  DATABASE_ERROR = 'DATABASE_ERROR',
  
  // 未知错误
  UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}

export enum ErrorSeverity {
  LOW = 'low',
  MEDIUM = 'medium',
  HIGH = 'high',
  CRITICAL = 'critical'
}

export interface ErrorContext {
  userId?: string
  taskId?: string
  accountId?: string
  component?: string
  action?: string
  metadata?: Record<string, any>
}

export interface AppError {
  code: ErrorCode
  message: string
  severity: ErrorSeverity
  context?: ErrorContext
  originalError?: Error
  timestamp: Date
  stack?: string
  retryable: boolean
}

// ============================================================================
// 自定义错误类
// ============================================================================

export class CustomError extends Error implements AppError {
  public readonly code: ErrorCode
  public readonly severity: ErrorSeverity
  public readonly context?: ErrorContext
  public readonly originalError?: Error
  public readonly timestamp: Date
  public readonly retryable: boolean

  constructor(
    code: ErrorCode,
    message: string,
    severity: ErrorSeverity = ErrorSeverity.MEDIUM,
    context?: ErrorContext,
    originalError?: Error,
    retryable: boolean = false
  ) {
    super(message)
    this.name = 'CustomError'
    this.code = code
    this.severity = severity
    this.context = context!
    this.originalError = originalError!
    this.timestamp = new Date()
    this.retryable = retryable

    // 保持错误堆栈
    if (originalError?.stack) {
      this.stack = originalError.stack
    } else if (Error.captureStackTrace) {
      Error.captureStackTrace(this, CustomError)
    }
  }

  toJSON() {
    return {
      name: this.name,
      code: this.code,
      message: this.message,
      severity: this.severity,
      context: this.context,
      timestamp: this.timestamp.toISOString(),
      retryable: this.retryable,
      stack: this.stack
    }
  }
}

// ============================================================================
// 错误处理器
// ============================================================================

export class ErrorHandler {
  private static instance: ErrorHandler
  private errorListeners: Array<(error: AppError) => void> = []

  static getInstance(): ErrorHandler {
    if (!ErrorHandler.instance) {
      ErrorHandler.instance = new ErrorHandler()
    }
    return ErrorHandler.instance
  }

  /**
   * 处理错误
   */
  handle(error: Error | AppError, context?: ErrorContext): AppError {
    let appError: AppError

    if (error instanceof CustomError) {
      appError = error
    } else {
      appError = this.createAppError(error as Error, context)
    }

    // 记录错误日志
    this.logError(appError)

    // 通知错误监听器
    this.notifyListeners(appError)

    return appError
  }

  /**
   * 创建应用错误
   */
  private createAppError(error: Error, context?: ErrorContext): AppError {
    const code = this.determineErrorCode(error)
    const severity = this.determineSeverity(code)
    const retryable = this.isRetryable(code)

    return new CustomError(
      code,
      error.message || '未知错误',
      severity,
      context,
      error,
      retryable
    )
  }

  /**
   * 确定错误代码
   */
  private determineErrorCode(error: Error): ErrorCode {
    const message = error.message.toLowerCase()

    // 网络错误
    if (message.includes('network') || message.includes('fetch')) {
      return ErrorCode.NETWORK_ERROR
    }
    if (message.includes('timeout')) {
      return ErrorCode.TIMEOUT_ERROR
    }
    if (message.includes('connection refused')) {
      return ErrorCode.CONNECTION_REFUSED
    }

    // 认证错误
    if (message.includes('unauthorized') || message.includes('401')) {
      return ErrorCode.AUTH_FAILED
    }
    if (message.includes('token') && message.includes('expired')) {
      return ErrorCode.TOKEN_EXPIRED
    }
    if (message.includes('forbidden') || message.includes('403')) {
      return ErrorCode.PERMISSION_DENIED
    }

    // 数据错误
    if (message.includes('validation') || message.includes('invalid')) {
      return ErrorCode.VALIDATION_ERROR
    }
    if (message.includes('not found') || message.includes('404')) {
      return ErrorCode.DATA_NOT_FOUND
    }

    // 业务错误
    if (message.includes('rate limit')) {
      return ErrorCode.RATE_LIMITED
    }

    return ErrorCode.UNKNOWN_ERROR
  }

  /**
   * 确定错误严重程度
   */
  private determineSeverity(code: ErrorCode): ErrorSeverity {
    switch (code) {
      case ErrorCode.INTERNAL_ERROR:
      case ErrorCode.DATABASE_ERROR:
        return ErrorSeverity.CRITICAL

      case ErrorCode.AUTH_FAILED:
      case ErrorCode.PERMISSION_DENIED:
      case ErrorCode.TASK_FAILED:
        return ErrorSeverity.HIGH

      case ErrorCode.NETWORK_ERROR:
      case ErrorCode.TIMEOUT_ERROR:
      case ErrorCode.VALIDATION_ERROR:
        return ErrorSeverity.MEDIUM

      default:
        return ErrorSeverity.LOW
    }
  }

  /**
   * 判断错误是否可重试
   */
  private isRetryable(code: ErrorCode): boolean {
    const retryableCodes = [
      ErrorCode.NETWORK_ERROR,
      ErrorCode.TIMEOUT_ERROR,
      ErrorCode.CONNECTION_REFUSED,
      ErrorCode.RATE_LIMITED
    ]
    return retryableCodes.includes(code)
  }

  /**
   * 记录错误日志
   */
  private logError(error: AppError): void {
    const logData = {
      code: error.code,
      message: error.message,
      severity: error.severity,
      context: error.context,
      timestamp: error.timestamp,
      stack: error.stack
    }

    switch (error.severity) {
      case ErrorSeverity.CRITICAL:
        logger.error('Critical error occurred', logData)
        break
      case ErrorSeverity.HIGH:
        logger.error('High severity error', logData)
        break
      case ErrorSeverity.MEDIUM:
        logger.warn('Medium severity error', logData)
        break
      case ErrorSeverity.LOW:
        logger.info('Low severity error', logData)
        break
    }
  }

  /**
   * 通知错误监听器
   */
  private notifyListeners(error: AppError): void {
    this.errorListeners.forEach(listener => {
      try {
        listener(error)
      } catch (err) {
        console.error('Error in error listener:', err)
      }
    })
  }

  /**
   * 添加错误监听器
   */
  addErrorListener(listener: (error: AppError) => void): void {
    this.errorListeners.push(listener)
  }

  /**
   * 移除错误监听器
   */
  removeErrorListener(listener: (error: AppError) => void): void {
    const index = this.errorListeners.indexOf(listener)
    if (index > -1) {
      this.errorListeners.splice(index, 1)
    }
  }
}

// ============================================================================
// 工具函数
// ============================================================================

/**
 * 全局错误处理器实例
 */
export const errorHandler = ErrorHandler.getInstance()

/**
 * 创建自定义错误
 */
export function createError(
  code: ErrorCode,
  message: string,
  severity?: ErrorSeverity,
  context?: ErrorContext,
  retryable?: boolean
): CustomError {
  return new CustomError(code, message, severity, context, undefined, retryable)
}

/**
 * 处理异步函数错误
 */
export function handleAsyncError<T>(
  promise: Promise<T>,
  context?: ErrorContext
): Promise<[AppError | null, T | null]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[AppError, null]>((error: Error) => [
      errorHandler.handle(error, context),
      null
    ])
}

/**
 * 错误重试装饰器
 */
export function withRetry<T extends (...args: any[]) => Promise<any>>(
  fn: T,
  maxRetries: number = 3,
  delay: number = 1000
): T {
  return (async (...args: Parameters<T>) => {
    let lastError: Error

    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      try {
        return await fn(...args)
      } catch (error) {
        lastError = error as Error
        
        const appError = errorHandler.handle(lastError)
        
        // 如果不可重试或已达到最大重试次数，抛出错误
        if (!appError.retryable || attempt === maxRetries) {
          throw appError
        }

        // 等待后重试
        await new Promise(resolve => setTimeout(resolve, delay * (attempt + 1)))
      }
    }

    throw lastError!
  }) as T
}
